﻿//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Ext.h".
//-------------------------------------------------------------------

#ifndef _UXS_CL_MEMORY_H
#define _UXS_CL_MEMORY_H

#pragma once

#include "CLDevice.h"
#include "CLEvent.h"
#include "CLQueue.h"

#ifdef _UXS_USE_OPENGL
#include "../../GL/shell/GLTexture.h"
#endif


namespace UX_STL
{
namespace CLShell
{

	//
	// CL Memory Object
	//

	class UX_EXPORT CLMemory : public CLBaseObject
	{
	protected:
		cl_mem		_pID;
		
	protected:
		virtual void _RetainRef()	const;
		virtual void _ReleaseRef()	const;
		virtual uint _GetRefCount()	const;
		virtual void _Destroy();

	public:
		CLMemory();
		~CLMemory();

		bool EnqueueUnmap(CLQueue *pQueue, void *pPtr, const clevent_uni_array &sEvents = clevent_uni_array(),
							CLEvent **pEvent = null);

		OPENGL_ONLY(
		bool GetGLObject(cl_gl_object::type &eType, GLuint &uIdent);
		)

		virtual void Destroy();

		cl_mem	Id() const	{ return _pID; }
	};



	//
	// CL Memory Objects Array
	//

	struct CLMemObjArray
	{
	public:
		typedef uni_array< CLMemory *>							mem_uni_array_t;
		typedef array< cl_mem, TFastCopyStrategy< cl_mem > >	clmem_array_t;

	private:
		clmem_array_t		_aMemArray;

	public:
		CLMemObjArray(const mem_uni_array_t &);

		operator const clmem_uni_array ()	const	{ return (clmem_uni_array)_aMemArray; }
	};



	//
	// CL Buffer
	//

	class UX_EXPORT CLBuffer : public CLMemory
	{
	public:
		CLBuffer();
		~CLBuffer();
		
		bool Create(usize uSize, cl_memory::type eFlags, void *pBuf = null);

		OPENGL_ONLY(
		bool Create(const GLShell::GLBuffer *pBuffer, cl_memory::type eFlags);
		)

		bool EnqueueRead(CLQueue *pQueue, bool bASync, usize uOffset, usize uDataSize, void *pData,
							const clevent_uni_array &aEvents = clevent_uni_array(), CLEvent **pEvent = null);

		bool EnqueueRead(CLQueue *pQueue, bool bASync, const svec3 &vBufOffset, const svec3 &vDataOffset,
							const svec3 &vDataSize, const svec2 &vBufRowSlicePitch,
							const svec2 &vDataRowSlicePitch, void *pData,
							const clevent_uni_array &aEvents = clevent_uni_array(), CLEvent **pEvent = null);

		bool EnqueueWrite(CLQueue *pQueue, bool bASync, usize uOffset, usize uDataSize, const void *pData,
							const clevent_uni_array &aEvents = clevent_uni_array(), CLEvent **pEvent = null);

		bool EnqueueWrite(CLQueue *pQueue, bool bASync, const svec3 &vBufOffset, const svec3 &vDataOffset,
							const svec3 &vDataSize, const svec2 &vBufRowSlicePitch,
							const svec2 &vDataRowSlicePitch, const void *pData,
							const clevent_uni_array &aEvents = clevent_uni_array(), CLEvent **pEvent = null);

		bool EnqueueMap(void *&pResult, CLQueue *pQueue, bool bASync, cl_map_flag::type eFlags, usize uOffset, usize uSize,
						const clevent_uni_array &aEvents = clevent_uni_array(), CLEvent **pEvent = null);
	};



	//
	// CL Image
	//

	class UX_EXPORT CLImage : public CLMemory
	{
	protected:
		svec3			_vTexDim;
		cl_img_format	_sFormat;

	public:
		CLImage();
		~CLImage();

		bool Create2D(const svec2 &vDim, cl_memory::type eFlags, const cl_img_format &sFormat,
						void *pImage = null, usize uRowPitch = 0);

		bool Create3D(const svec3 &vDim, cl_memory::type eFlags, const cl_img_format &sFormat,
						void *pImage = null, usize uRowPitch = 0, usize uSlicePitch = 0);

		OPENGL_ONLY(
			bool CreateFromTexture(const GLShell::GLTexture *pTexture, cl_memory::type eFlags, uint uMipmap = 0,
									GLShell::gl_cube_face::type eFace = GLShell::gl_cube_face::_UNKNOWN);

			bool CreateFromRenderbuffer(const GLShell::GLRenderBuffer *pRB, cl_memory::type eFlags);

			bool CreateFromTextureGL(GLenum eTarget, GLuint uID, cl_memory::type eFlags, uint uMipmap = 0);
		)

		void SwapData (CLImage &image);

		virtual void Destroy();
		
		bool EnqueueRead(CLQueue *pQueue, bool bASync, const svec3 &vOffset, const svec3 &vDataSize,
						const svec2 &vDataRowSlicePitch, void *pData,
						const clevent_uni_array &aEvents = clevent_uni_array(), CLEvent **pEvent = null);

		bool EnqueueWrite(CLQueue *pQueue, bool bASync, const svec3 &vOffset, const svec3 &vDataSize,
						const svec2 &vDataRowSlicePitch, const void *pData,
						const clevent_uni_array &aEvents = clevent_uni_array(), CLEvent **pEvent = null);

		bool EnqueueCopy(CLQueue *pQueue, CLImage *pSrcImage, const svec3 &vSrcOffset,
						const svec3 &vDstOffset, const svec3 &vSize,
						const clevent_uni_array &aEvents = clevent_uni_array(), CLEvent **pEvent = null);

		bool EnqueueCopy(CLQueue *pQueue, CLBuffer *pSrcBuf, usize uSrcOffset, const svec3 &vDstOffset, const svec3 &vSize,
						const clevent_uni_array &aEvents = clevent_uni_array(), CLEvent **pEvent = null);
						
		bool EnqueueCopyToBuffer(CLQueue *pQueue, CLBuffer *pDstBuf, const svec3 &vSrcOffset,
						const svec3 &vSize, usize uDstOffset,
						const clevent_uni_array &aEvents = clevent_uni_array(), CLEvent **pEvent = null);

		bool EnqueueMap(void *&pResult, svec2 &vRowSlicePitch, CLQueue *pQueue, bool bASync,
						cl_map_flag::type eFlags, const svec3 &vOffset, const svec3 &vSize, 
						const clevent_uni_array &aEvents = clevent_uni_array(), CLEvent **pEvent = null);

		bool					Is2D()			const	{ return _vTexDim.x != 0 and _vTexDim.y != 0 and _vTexDim.z == 0; }
		bool					Is3D()			const	{ return _vTexDim.x != 0 and _vTexDim.y != 0 and _vTexDim.z != 0; }
		const svec3 &			Dimension()		const	{ return _vTexDim; }
		cl_img_format const &	Format()		const	{ return _sFormat; }
		
		OPENGL_ONLY(
			static bool s_GLForamtToCLFormat (GLShell::gl_tex_iformat::type fmt, OUT cl_img_format &clFormat);
		)
	};



	
//-------------------------- CLMemObjArray ------------------------//

	inline CLMemObjArray::CLMemObjArray(const mem_uni_array_t &aMemObjs)
	{
		_aMemArray.Reserve( aMemObjs.Count() );

		FOR( i, aMemObjs ) {
			_aMemArray.PushBack( aMemObjs[i]->Id() );
		}
	}

//-------------------------------------------------------------------

}	// CLShell
}	// UX_STL

#endif	// _UXS_CL_MEMORY_H